﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Windows.Forms;

namespace ChartEdit
{

    public class ThemeManager : List<Theme>
    {
        public static string PATH = Path.Combine( Application.StartupPath, "themes" );

        public ThemeManager()
        {
        }

        public void LoadAll()
        {
            Clear();
            DirectoryInfo[] dirs = new DirectoryInfo( PATH ).GetDirectories();

            Load( "default" );

            foreach ( DirectoryInfo dir in dirs )
            {
                if ( dir.Name != "default" )
                    Load( dir.Name );
            }
        }
        public void Load( string fileName )
        {
            string fullPath = Path.Combine( PATH, fileName );
            fullPath = Path.Combine( fullPath, "theme.xml" );

            Theme theme = Theme.Load( fullPath );

            if ( theme == null )
                return;

            if ( !theme.LoadFiles() )
                return;

            this.Add( theme );
        }

        public bool ContainsTheme( string name )
        {
            foreach ( Theme theme in this )
            {
                if ( theme.Name == name )
                    return true;
            }
            return false;
        }

        public Theme this[ string name ]
        {
            get
            {
                foreach ( Theme theme in this )
                {
                    if ( theme.Name == name )
                        return theme;
                }
                return this[ 0 ];
            }
        }
    }

    public class Theme : Serializable<Theme>
    {
        //This is a very important value that is used for scaling
        public static float baseWidth = 133f;


        [XmlAttribute]
        public string Name;

        public string RenderOrder;

        [XmlIgnore]
        public List<int> RealRenderOrder;


        public List<ChartElement> Elements;
        public List<SpecialElement> Specials;

        public Theme()
        {
            Name = "";
            RenderOrder = "";

            RealRenderOrder = new List<int>();
            Elements = new List<ChartElement>();
            Specials = new List<SpecialElement>();
        }

        public bool LoadFiles()
        {
            string[] splits = RenderOrder.Split( " ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries );
            foreach ( string splitEntry in splits )
            {
                int orderEntry = 0;

                if ( !int.TryParse( splitEntry, out orderEntry ) )
                    continue;

                RealRenderOrder.Add( orderEntry );
            }

            foreach ( ChartElement element in Elements )
            {
                if ( !element.LoadFiles( Name ) )
                    return false;
            }
            foreach (SpecialElement element in Specials)
            {
                if (!element.LoadFiles(Name))
                    return false;
            }
            return true;
        }

        public void Resize(int width)
        {
            foreach (ChartElement cE in Elements)
            {
                cE.ResizeImages(width);
            }
            foreach (SpecialElement sE in Specials)
            {
                sE.ResizeImage(width);
            }
        }

        public ChartElement this[ int index ]
        {
            get
            {
                if (index >= 0 & index < Elements.Count)
                    return Elements[index];
                else
                
                {
                    //*
                    ChartElement ce = new ChartElement();
                    ce.Parts.Add(new ChartElementPart());
                    ce[0].ImagePath = Elements[0][0].ImagePath;
                    ce[0].Image = (Image)(new Bitmap(2, 2));
                    ce.Name = "invalid";
                    ce.Color = new ChartColor(0,0,0,0,0);
                    ce.BoundingBox = new ChartBB(0, 0, 0, 0);
                    ce.Offset = new ChartPoint(-2000, 0);
                    ce.FretIndex = 0;
                    return ce;//CHANGE THIS TO SOME SPECIAL INVALID NOTE LATER
                    //*/
                    //return Elements[0];
                }
            }

            
        }
    }

    public class ChartElementPart
    {
        [XmlAttribute]
        public string Name;

        [XmlAttribute]
        public string ImagePath;

        [XmlAttribute]
        public double SpinRate;

        [XmlIgnore]
        public Image Image { get; set; }
        [XmlIgnore]
        public Image ImageResized { get; set; }



        public ChartElementPart()
        {
            Name = "";
            ImagePath = "";
        }

        public void ResizeImage( int width, ChartBB boundingBox )
        {

            //int baseHeight = 385;//probably not going to use this one
            float mult = (float)width / Theme.baseWidth;
            Size size = this.Image.Size;

            int newWidth = ( int )( mult * boundingBox.Width );
            int newHeight = ( int )( mult * boundingBox.Height );
            Bitmap b;
            Graphics g;
            b = new Bitmap( newWidth, newHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb );
            //b.
            //b.Size=
            g = Graphics.FromImage( ( Image )b );
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            
            g.DrawImage( this.Image, 0, 0, newWidth, newHeight );

            ImageResized = ( Image )b;

            GC.Collect();
        }

        public bool LoadFiles( string themeName, ChartBB boundingBox )
        {
            try
            {
                string fullPath = Path.Combine( ThemeManager.PATH, themeName );
                fullPath = Path.Combine( fullPath, "images" );
                fullPath = Path.Combine( fullPath, ImagePath );

                this.Image = System.Drawing.Image.FromFile( fullPath );

                ResizeImage( 100, boundingBox );

                return true;
            }
            catch
            {
                return false;
            }
        }
    }
    public class SpecialElement
    {
        [XmlAttribute]
        public string Name;
        public string ConcatenationString;
        public int SpecialIndex;

        [XmlAttribute]
        public string ImagePath;
        [XmlIgnore]
        public Image Image;
        [XmlIgnore]
        public Image ImageResized;


        public ChartBB BoundingBox;
        [XmlIgnore]
        public ChartBB BoundingBoxResized;
        public ChartBB BoundingBox2;

        public ChartPoint Edges;
        [XmlIgnore]
        public float LX;
        [XmlIgnore]
        public float RX;

        public ChartPoint Offset;
        public ChartColor Color;
        [XmlIgnore]
        public SolidBrush Brush;

        public void ResizeImage(int width)
        {
            float mult = (float)width / Theme.baseWidth;
            Size size = this.Image.Size;

            int newWidth = (int)(mult * BoundingBox.Width);
            int newHeight = (int)(mult * BoundingBox.Height);
            Bitmap b;
            Graphics g;
            b = new Bitmap(newWidth, newHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            //b.
            //b.Size=
            g = Graphics.FromImage((Image)b);
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

            g.DrawImage(this.Image, 0, 0, newWidth, newHeight);

            ImageResized = (Image)b;

            GC.Collect();
        }

        public bool LoadFiles(string themeName)
        {
            Brush = new SolidBrush(System.Drawing.Color.FromArgb(Color.A, Color.R, Color.G, Color.B));
            LX = Edges.X;
            RX = Edges.Y;
            try
            {
                string fullPath = Path.Combine(ThemeManager.PATH, themeName);
                fullPath = Path.Combine(fullPath, "images");
                fullPath = Path.Combine(fullPath, ImagePath);

                this.Image = System.Drawing.Image.FromFile(fullPath);

                ResizeImage(100);
            }
            catch
            {
                return false;
            }
            return true;
        }

        public SpecialElement()
        {
            Name = "";
            ImagePath = "";
            ConcatenationString = "";
        }

    }
    public class ChartElement
    {
        [XmlAttribute]
        public string Name;

        public int FretIndex;

        public ChartBB BoundingBox;
        public ChartBB BoundingBoxResized;
        public ChartBB BoundingBox2;

        public ChartPoint Offset;

        public ChartColor Color;
        
        [XmlIgnore]
        public Pen SustainPen { get; set; }

        public List<ChartElementPart> Parts;


        public ChartElement()
        {
            Name = "";
            Parts = new List<ChartElementPart>();
        }


        public bool LoadFiles( string themeName )
        {
            SustainPen = new Pen( System.Drawing.Color.FromArgb( Color.A, Color.R, Color.G, Color.B ), Color.BrushSize );

            foreach ( ChartElementPart part in Parts )
            {
                if ( !part.LoadFiles( themeName, BoundingBox )  )
                    return false;
            }
            return true;
        }

        public void ResizeImages(int width)
        {
            float m = (float)width/Theme.baseWidth;
            this.BoundingBoxResized = new ChartBB(BoundingBox.X * m, BoundingBox.Y * m,
                BoundingBox.Width * m, BoundingBox.Height * m);
            foreach (ChartElementPart cEP in Parts)
            {
                cEP.ResizeImage(width, this.BoundingBox);
            }
        }

        public ChartElementPart this[ int index ]
        {
            get
            {
                return Parts[ index ];
            }
        }
        public ChartElementPart this[ string name ]
        {
            get
            {
                foreach ( ChartElementPart part in Parts )
                {
                    if ( part.Name == name )
                        return part;
                }
                return Parts[ 0 ];
            }
        }
    }

    public class ChartColor
    {
        [XmlAttribute]
        public int A;
        [XmlAttribute]
        public int R;
        [XmlAttribute]
        public int G;
        [XmlAttribute]
        public int B;

        [XmlAttribute]
        public int BrushSize;

        public ChartColor()
        {
        }
        public ChartColor( int a, int r, int g, int b, int brushSize )
        {
            A = a;
            R = r;
            G = g;
            B = b;

            BrushSize = brushSize;
        }
        public ChartColor(Color color, int brushSize)
        {
            A = color.A;
            R = color.R;
            G = color.G;
            B = color.B;

            BrushSize = brushSize;
        }
    }
    public class ChartPoint
    {
        [XmlAttribute]
        public float X;
        [XmlAttribute]
        public float Y;

        public ChartPoint()
        {
        }
        public ChartPoint( float x, float y )
        {
            X = x;
            Y = y;
        }
    }
    public class ChartBB
    {
        [XmlAttribute]
        public float X;
        [XmlAttribute]
        public float Y;

        [XmlAttribute]
        public float Width;
        [XmlAttribute]
        public float Height;

        public PointF XY
        {
            get { return new PointF(X, Y); }
            set
            {
                X = value.X;
                Y = value.Y;
            }
        }
        public ChartBB()
        {
        }
        public ChartBB( float x, float y, float width, float height )
        {
            X = x;
            Y = y;
            Width = width;
            Height = height;
        }
    }
}
